home *** CD-ROM | disk | FTP | other *** search
- /* Functions for reading from and writing to files. For files opened
- with fsRdWrShPerm there are functions which implement range locking.
- You can also specify that the area being written to or read from be
- automatically locked while writing (or reading) and unlocked when
- finished writing (or reading). For writing, you can enable automatic
- verfication, so that a read verify operation will be performed after
- each write. A few of the functions are slightly inefficient: before
- every operation the entire parameter block is cleared with a call
- to memclr, even though only a few fields may actually need to be
- cleared. However, in the interests of correctness, I decided to
- retain the calls to memclr.
-
- Revision History:
-
- 93/03/23 AIH
- - Made buffer parameters to file writing functions const
-
- 91/11/14 AIH
- - Removed checks for system software prior to version 7.0
-
- 91/06/13 AIH
- - Time library is used to delay so that background tasks get time
-
- 91/05/31 AIH
- - Added assertion to prevent a bug with _PBLockRange in system software
- 6.0.7 and earlier. This bug is documented in TN186.
-
- 91/05/16 AIH
- - Added a few comments
-
- 91/04/20 Ari Halberstadt (AIH)
- - Added automatic write verify function */
-
- #include <limits.h>
- #include <string.h>
- #include "MacLib.h"
- #include "MemoryLib.h"
- #include "TimeLib.h"
- #include "StringLib.h"
- #include "TimeLib.h"
- #include "FileLib.h"
-
- /*----------------------------------------------------------------------------*/
- /* locking and unlocking ranges */
- /*----------------------------------------------------------------------------*/
-
- /* turn automatic range locking on or off */
- void FileAutoLockSet(FileType *fp, Boolean lock)
- {
- fp->lock = lock;
- }
-
- /* lock count bytes following the specified position */
- void FileRangeLock(FileType *fp, FilePosType count, FilePosType pos)
- {
- const TicksType wait = 5; /* ticks to wait after each failure */
- const short maxtry = 6; /* maximum number of attempts to lock range */
- volatile short try = 0; /* number of attempts to lock the range */
- ParamBlockRec pb;
-
- require(FileValid(fp));
- require(fp->ref != FILE_CLOSED);
- TRY {
- /* Try to lock the range. After each failure, wait several ticks
- before trying again. Give up after too many failures. */
- memclr(&pb, sizeof(ParamBlockRec));
- pb.ioParam.ioRefNum = fp->ref;
- pb.ioParam.ioReqCount = count;
- pb.ioParam.ioPosMode = fsFromStart;
- pb.ioParam.ioPosOffset = pos;
- FailOSErr(PBLockRange(&pb, false));
- } CATCH {
- if (++try < maxtry) {
- TimeDelay(wait);
- RETRY;
- }
- } ENDTRY;
- }
-
- /* unlock count bytes following the specified position */
- void FileRangeUnlock(FileType *fp, FilePosType count, FilePosType pos)
- {
- ParamBlockRec pb;
-
- require(FileValid(fp));
- require(fp->ref != FILE_CLOSED);
- memclr(&pb, sizeof(ParamBlockRec));
- pb.ioParam.ioRefNum = fp->ref;
- pb.ioParam.ioReqCount = count;
- pb.ioParam.ioPosMode = fsFromStart;
- pb.ioParam.ioPosOffset = pos;
- FailOSErr(PBUnlockRange(&pb, false));
- }
-
- /*----------------------------------------------------------------------------*/
- /* write verification */
- /*----------------------------------------------------------------------------*/
-
- /* turn automatic write verification on or off */
- void FileVerifySet(FileType *fp, Boolean verify)
- {
- fp->verify = verify;
- }
-
- /*----------------------------------------------------------------------------*/
- /* reading and writing */
- /*----------------------------------------------------------------------------*/
-
- /* this is very similar to FSRead */
- FilePosType FileRead(FileType *fp, FilePosType count, void *buffer)
- {
- OSErr err;
-
- require(FileValid(fp));
- require(fp->ref != FILE_CLOSED);
- require(count >= 0);
- err = FSRead(fp->ref, &count, buffer);
- if (err == eofErr)
- err = noErr;
- FailOSErr(err);
- return(count);
- }
-
- /* This is very similar to FSWrite. If the file's lock attribute is set then
- the range to be read is locked and then unlocked. If the file's verify
- attribute is set then the write is verified. */
- void FileWrite(FileType *fp, FilePosType count, const void *buffer)
- {
- volatile FilePosType pos; /* current position in file */
- volatile Boolean locked; /* true if we did range locking */
- FilePosType actcnt; /* actual number of bytes written */
- ParamBlockRec pb; /* for verifying the write */
- OSErr err = noErr;
-
- require(FileValid(fp));
- require(fp->ref != FILE_CLOSED);
- require(count >= 0);
- TRY {
- /* lock the range if auto-locking is enabled */
- locked = false;
- if (fp->lock) {
- pos = FilePosition(fp);
- FileRangeLock(fp, count, pos);
- locked = true;
- }
- /* write */
- actcnt = count;
- FailOSErr(FSWrite(fp->ref, &actcnt, (Ptr) buffer));
- check(actcnt == count);
- if (fp->verify) {
- /* verify write */
- memclr(&pb, sizeof(ParamBlockRec));
- pb.ioParam.ioRefNum = fp->ref;
- pb.ioParam.ioBuffer = (void *) buffer;
- pb.ioParam.ioReqCount = count;
- pb.ioParam.ioPosMode = rdVerify;
- err = PBRead(&pb, false);
- if (err == eofErr) /* reaching the eof on a read isn't an error */
- err = noErr;
- FailOSErr(err);
- }
- } CLEANUP {
- if (locked)
- FileRangeUnlock(fp, count, pos);
- } ENDTRY;
- }
-
- /*----------------------------------------------------------------------------*/
- /* reading and writing a single character (not very efficient) */
- /*----------------------------------------------------------------------------*/
-
- /* read one character from the file */
- Boolean FileReadChar(FileType *fp, char *c)
- {
- return(FileRead(fp, 1, c) == 1);
- }
-
- /* write one character to the file */
- void FileWriteChar(FileType *fp, char c)
- {
- FileWrite(fp, 1, &c);
- }
-
- /*----------------------------------------------------------------------------*/
- /* reading and writing strings */
- /*----------------------------------------------------------------------------*/
-
- /* Read a string terminated with the 'stop' character from the file.
- At most 'count' characters are read, and the terminating character
- is discarded. The resulting string is null terminated. The
- length of the string is returned (ie, number of
- characters read minus 1). */
- FilePosType FileReadStr(FileType *fp, FilePosType count, char *str, char stop)
- {
- ParamBlockRec pb;
- Boolean result = false;
- OSErr err = noErr;
-
- require(FileValid(fp));
- require(fp->ref != FILE_CLOSED);
- require(count >= 0);
- /* IM-IV, p121 describes the flags to ioPosMode */
- pb.ioParam.ioCompletion = 0;
- pb.ioParam.ioRefNum = fp->ref;
- pb.ioParam.ioBuffer = str;
- pb.ioParam.ioReqCount = count;
- pb.ioParam.ioPosMode = (fsAtMark | 0x80 | (stop << CHAR_BIT));
- pb.ioParam.ioPosOffset = 0;
- err = PBRead(&pb, false);
- if (err == eofErr)
- err = noErr;
- FailOSErr(err);
- count = pb.ioParam.ioActCount;
- str[pb.ioParam.ioActCount] = 0;
- ensure(strlen(str) == count + 1);
- return(count);
- }
-
- /* write the null terminated string to the file */
- void FileWriteStr(FileType *fp, const char *str)
- {
- FileWrite(fp, strlen(str), str);
- }
-
- /* read a line with at most 'count' characters from the file */
- FilePosType FileReadLine(FileType *fp, FilePosType count, char *line)
- {
- return(FileReadStr(fp, count, line, '\r'));
- }
-
- /* flush the volume on which the file resides */
- void FileFlush(FileType *fp)
- {
- require(FileValid(fp));
- FailOSErr(FlushVol((StringPtr) "", fp->vol));
- }
-
-